/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.commons;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * JSON序列化工具
 * https://www.cnblogs.com/christopherchan/p/11071098.html
 */
class JacksonUtils {

    private static ObjectMapper objectMapper = new ObjectMapper();
    // 日起格式化
    private static final String STANDARD_FORMAT =  "yyyy-MM-dd'T'HH:mm:ss.SSSZ";//"yyyy-MM-dd HH:mm:ss";
    private static final String STANDARD_FORMAT2 = "yyyy-MM-dd'T'HH:mm:ss.SSS a";

    static {
        //对象的所有字段全部列入
        objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
        //取消默认转换timestamps形式
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
        //忽略空Bean转json的错误
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS,false);
        //所有的日期格式都统一为以下的样式，即yyyy-MM-dd HH:mm:ss
//        objectMapper.setDateFormat(new SimpleDateFormat(STANDARD_FORMAT));
        //忽略 在json字符串中存在，但是在java对象中不存在对应属性的情况。防止错误
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
        //设置可用单引号
        objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        //设置字段可以不用双引号包括
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);

        //https://blog.csdn.net/qfzhangwei/article/details/85009163
        objectMapper.configure(JsonGenerator.Feature.IGNORE_UNKNOWN,true);
        objectMapper.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN,true);
        //允许缺少数据
        objectMapper.configure(JsonParser.Feature.ALLOW_MISSING_VALUES,true);
        //大小写脱敏 默认为false  需要改为true
        objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES,true);
        //OffsetTimeDate保留时区
        objectMapper.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);

        //这里处理是为了兼容N版的序列化日期的格式
        JavaTimeModule module = new JavaTimeModule();
        LocalDateTimeDeserializer deserializer = new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(STANDARD_FORMAT2));
        module.addDeserializer(LocalDateTime.class, deserializer);
        objectMapper.registerModule(module);
    }

    /**
     * 对象转Json格式字符串
     * @param obj 对象
     * @return Json格式字符串
     */
    public static <T> String serialize(T obj) {
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            System.out.println(String.format("Parse Object to String error : %s", e.getMessage()));
            return null;
        }
    }

    /**
     * 对象转Json格式字符串(格式化的Json字符串)
     * @param obj 对象
     * @return 美化的Json格式字符串
     */
    public static <T> String serializePretty(T obj) throws Exception {
        try {
            return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new Exception(String.format("Parse Object to String error : %s", e.getMessage()));
        }
    }

    /**
     * 字符串转换为自定义对象
     * @param str 要转换的字符串
     * @param clazz 自定义对象的class对象
     * @return 自定义对象
     */
    public static <T> T deserialize(String str, Class<T> clazz) {
        //反序列化时空串【""】会报错，正常的空串应该【""""】
        if(isEmpty(str) || clazz == null){
            return null;
        }
        try {
            //return clazz.equals(String.class) ? (T) str : objectMapper.readValue(str, clazz);
            return objectMapper.readValue(str, clazz);
        } catch (Exception e) {
            System.out.println(String.format("Parse Object to String error : %s", e.getMessage()));
            return null;
        }
    }

    public static <T> T deserialize(String str, JavaType javaType){
        if(isEmpty(str)||javaType==null){
            return null;
        }
        try{
            return objectMapper.readValue(str,javaType);
        }catch (Exception e){
            System.out.println(String.format("Parse Object to String error : %s", e.getMessage()));
            return null;
        }
    }

    /**
     * 实体对象转换成Json字符串
     * @param str 实体对象T
     * @return T
     */
    public static <T> T deserialize(String str, Class<?> collectionClazz, Class<?>... elementClazzes) {
        //反序列化时空串【""】会报错，正常的空串应该【""""】
        if (isEmpty(str) || collectionClazz == null || elementClazzes==null) {
            return null;
        }
        JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClazz, elementClazzes);
        try {
            return objectMapper.readValue(str, javaType);
        } catch (IOException e) {
            System.out.println(String.format("Parse Object to String error : %s", e.getMessage()));
            return null;
        }
    }

    /**
     * 实体对象转换成Json字符串
     * @param cs 实体对象T
     * @return boolean
     */

    private static boolean isEmpty(CharSequence cs){
        return (cs == null) || (cs.length() == 0);
    }

    public static ObjectMapper getObjectMapper(){
        return objectMapper;
    }
}
